home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_098 / hddriver / driver / lib.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  7KB  |  286 lines

  1.  
  2. /*
  3.  * Copyright 1987 Alan Kent
  4.  *
  5.  * Permission is granted to redistribute this code as long
  6.  * as this message is retained in the code and the code is
  7.  * not sold without written permission from the author.
  8.  *
  9.  * UUCP: {seismo,hplabs,mcvax,ukc,nttlab}!munnari!goanna.oz!ajk
  10.  * ACSnet: ajk@goanna.oz
  11.  * ARPA: munnari!goanna.oz!ajk@SEISMO.ARPA
  12.  */
  13.  
  14.  
  15. #include "hd.h"
  16.  
  17.  
  18. /* initialize library node */
  19.  
  20. LONG
  21. cLibInit ( dev , seg_list )
  22. struct hd_dev *dev;
  23. BPTR seg_list;        /* I think its BPTR */
  24. {
  25.     int i;
  26.     struct hd_unit *unit;
  27.     struct Process *process;
  28.  
  29.  
  30.     /* easier here than trying to use the automatic initalization */
  31.  
  32.     dev->hd_Dev.dd_Library.lib_Node.ln_Type = NT_DEVICE;
  33.     dev->hd_Dev.dd_Library.lib_Node.ln_Name = dev_name;
  34.     dev->hd_Dev.dd_Library.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
  35.     dev->hd_Dev.dd_Library.lib_Version = HD_VERSION;
  36.     dev->hd_Dev.dd_Library.lib_Revision = HD_REVISION;
  37.     dev->hd_Dev.dd_Library.lib_IdString = (APTR)dev_id_string;
  38.  
  39.     /* Initiate controller. Actually, this is being a bit naughty. */
  40.     /* The signals should be allocated in the created subtask, but */
  41.     /* I know the subtask does not allocate any signals itself so */
  42.     /* any signal we create will be ok. The signal is created for */
  43.     /* the interrupt driven controller */
  44.  
  45.     if ( wd_open () < 0 )
  46.         return ( NULL );
  47.  
  48.     /* create a single global port on which ALL messages for all devices */
  49.     /* and units will arrive. Note that CreatePort allocates a signal. */
  50.     /* See the above discussion about signals and wd_open() */
  51.  
  52.     port = CreatePort ( (char*)NULL , (LONG)0 );
  53.     if ( port == NULL ) {
  54.         wd_close ();
  55.         return ( NULL );
  56.     }
  57.  
  58.     /* initiate cache */
  59.  
  60.     if ( init_cache () < 0 ) {
  61.         wd_close ();
  62.         DeletePort ( port );
  63.         return ( NULL );
  64.     }
  65.  
  66.     /* Create a single task to be shared by all units. */
  67.     /* This is to ensure exclusive access to the controller. */
  68.     /* Note that the caching at present will only work with a */
  69.     /* single unit */
  70.  
  71.     process = CreateProc ( dev_name ,
  72.         (LONG)HD_PRIORITY ,
  73.         (LONG)proc_seg_list >> 2L ,
  74.         (LONG)HD_STACKSIZE );
  75.  
  76.     if ( process == NULL ) {
  77.         free_cache ();
  78.         wd_close ();
  79.         DeletePort ( port );
  80.         return ( NULL );
  81.     }
  82.  
  83.     /* actually, CreateProc returns a pointer to the message port */
  84.     /* to use with C, must adjust to start of procedure */
  85.  
  86.     process = PROCPTR ( process );
  87.  
  88.     /* ok, now anything to do with controller is for subtask. */
  89.     /* When wd_open was called, it initialized the interrupts to */
  90.     /* send an interrupt to this task. Now interrupts should be */
  91.     /* sent to the subprocess. */
  92.  
  93.     wd_subtask ( &process->pr_Task );
  94.  
  95.     /* similarly, the port should send message port signals to the task */
  96.  
  97.     port->mp_SigTask = &process->pr_Task;
  98.  
  99.     /* initialize all units */
  100.  
  101.     for ( i = 0; i < HD_NUMUNITS; i++ ) {
  102.  
  103.         unit = &dev->hd_Unit[i];
  104.  
  105.         unit->hdu_Unit.unit_OpenCnt = 0;
  106.         unit->hdu_Unit.unit_MsgPort = port;
  107.         unit->hdu_UnitNum = i;
  108.         unit->hdu_Task = &process->pr_Task;    /* shared */
  109.     }
  110.     return ( (LONG)dev );
  111. }
  112.  
  113.  
  114.  
  115. /* actually, cOpen does not need to return anything, but libraries do, */
  116. /* so I am returning the device pointer just to be safe */
  117.  
  118. struct hd_dev *
  119. cOpen ( dev , ior , unit_num , flags )
  120. struct hd_dev *dev;
  121. struct IOExtHD *ior;
  122. LONG unit_num;
  123. ULONG flags;
  124. {
  125.     register struct hd_unit *unit;
  126.  
  127.  
  128.     ior->iohd_TD.iotd_Req.io_Error = 0;
  129.  
  130.     /* check for legal unit number */
  131.  
  132.     if ( unit_num < 0  ||  unit_num >= HD_NUMUNITS ) {
  133.         ior->iohd_TD.iotd_Req.io_Error = TDERR_BadUnitNum;
  134.         return ( NULL );
  135.     }
  136.  
  137.     unit = &dev->hd_Unit[ unit_num ];
  138.  
  139.     /* set up request, unit, open counts, and we no longer want to expunge */
  140.     /* the library when all closes are done */
  141.  
  142.     ior->iohd_TD.iotd_Req.io_Unit = &unit->hdu_Unit;
  143.     dev->hd_Flags &= ~ (ULONG) LIBF_DELEXP;
  144.     dev->hd_Dev.dd_Library.lib_OpenCnt++;
  145.     unit->hdu_Unit.unit_OpenCnt++;
  146.     return ( dev );
  147. }
  148.  
  149.  
  150. BPTR        /* seg list */
  151. cClose ( dev , ior )
  152. struct hd_dev *dev;
  153. struct IOExtHD *ior;
  154. {
  155.  
  156.     ior->iohd_TD.iotd_Req.io_Error = 0;
  157.  
  158.     if ( --(ior->iohd_TD.iotd_Req.io_Unit->unit_OpenCnt) == 0 ) {
  159.  
  160.         /* expunge unit */
  161.  
  162.         /* well, actually we have only one task for all units so dont */
  163.         /* kill the unit task */
  164.     }
  165.  
  166.     /* clear out ior so that it cant be accidently reused */
  167.  
  168.     ior->iohd_TD.iotd_Req.io_Unit = NULL;
  169.     ior->iohd_TD.iotd_Req.io_Device = NULL;
  170.  
  171.     /* one less person using the device driver */
  172.  
  173.     if ( --(dev->hd_Dev.dd_Library.lib_OpenCnt) <= 0
  174.     &&  ( dev->hd_Flags & LIBF_DELEXP ) )
  175.  
  176.         /* no one has us open anymore and we have a delayed expunge */
  177.         /* command pending, so do it! */
  178.  
  179.         return ( cExpunge ( dev ) );
  180.  
  181.     return ( NULL );
  182. }
  183.  
  184.  
  185. BPTR        /* seg list */
  186. cExpunge ( dev )
  187. struct hd_dev *dev;
  188. {
  189.     BPTR seg_list;
  190.  
  191.     if ( dev->hd_Dev.dd_Library.lib_OpenCnt > 0 ) {
  192.  
  193.         /* someone still has the library open - mark that should be */
  194.         /* deleted when everyone has closed us */
  195.  
  196.         dev->hd_Flags |= LIBF_DELEXP;
  197.         return ( NULL );
  198.     }
  199.  
  200.     /* stop anyone else from opening the device */
  201.  
  202.     Remove ( dev );
  203.  
  204.     free_cache ();
  205.     wd_close ();
  206.     DeletePort ( port );
  207.     CloseLibrary ( DOSBase );
  208.     seg_list = dev->hd_SegList;
  209.  
  210.     FreeMem ( ((char *)dev) - dev->hd_Dev.dd_Library.lib_NegSize ,
  211.         (LONG) dev->hd_Dev.dd_Library.lib_NegSize
  212.         + (LONG) dev->hd_Dev.dd_Library.lib_PosSize );
  213.  
  214.     return ( seg_list );
  215. }
  216.  
  217.  
  218.  
  219. void
  220. cBeginIO ( dev , ior )
  221. struct hd_dev *dev;
  222. struct IOExtHD *ior;
  223. {
  224.  
  225.     ior->iohd_TD.iotd_Req.io_Error = 0;
  226.  
  227.  
  228.     /* If some commands can be done very quickly, then a call to */
  229.     /* perform_io () could be made. Care must be taken to ensure */
  230.     /* that the disk driver task is not in perform_io () at the */
  231.     /* same time so some global lock variable should be used. */
  232.     /* Also, if the device has been stopped with CMD_STOP, we should */
  233.     /* not try to do the command immediately. When the command cannot */
  234.     /* be done immediately, the requests must be queued by sending */
  235.     /* them to the task. For safty, Disable() and Enable() may need to */
  236.     /* be called to safely examine and modify global variables. */
  237.  
  238.     /* In the device driver, the status commands must always work */
  239.     /* immediately and cannot do a Wait() as they are called from */
  240.     /* interrupts too (and so use the interrupt stack). (Well, thats */
  241.     /* what the manual said anyway). Since for a harddisk the code */
  242.     /* is so trivial, it was repeated here rather than calling */
  243.     /* perform_io(). */
  244.  
  245.     if ( ( ior->iohd_TD.iotd_Req.io_Command & ~(ULONG)TDF_EXTCOM ) > HD_LASTCOMM ) {
  246.         ior->iohd_TD.iotd_Req.io_Error = IOERR_NOCMD;
  247.         return;
  248.     }
  249.  
  250.     switch ( (int) ior->iohd_TD.iotd_Req.io_Command ) {
  251.  
  252.     case TD_CHANGENUM :
  253.         ior->iohd_TD.iotd_Req.io_Actual = CHANGE_COUNT;
  254.         break;
  255.  
  256.     case TD_CHANGESTATE :
  257.         ior->iohd_TD.iotd_Req.io_Actual = 0;
  258.         break;
  259.  
  260.     case TD_PROTSTATUS :
  261.         ior->iohd_TD.iotd_Req.io_Actual = 0;
  262.         break;
  263.  
  264.     default :
  265.         /* clear quick flag to say that message is going to be queued */
  266.  
  267.         ior->iohd_TD.iotd_Req.io_Flags &= ~ (ULONG) IOF_QUICK;
  268.         PutMsg ( ior->iohd_TD.iotd_Req.io_Unit->unit_MsgPort , ior );
  269.         break;
  270.     }
  271. }
  272.  
  273.  
  274.  
  275. void
  276. cAbortIO ( dev , ior )
  277. struct hd_dev *dev;
  278. struct IOExtHD *ior;
  279. {
  280.  
  281.     ior->iohd_TD.iotd_Req.io_Error = 0;
  282.  
  283.     /* can any of the commands be aborted? */
  284. }
  285.  
  286.